home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / gnuish / mkinf10 / makeinfo.e < prev    next >
Text File  |  1990-11-01  |  40KB  |  1,817 lines

  1. /* Makeinfo -- convert texinfo format files into info files
  2.  
  3.    Copyright (C) 1987 Free Software Foundation, Inc.
  4.  
  5.    This file is part of GNU Info.
  6.  
  7.    Makeinfo is distributed in the hope that it will be useful,
  8.    but WITHOUT ANY WARRANTY.  No author or distributor accepts
  9.    responsibility to anyone for the consequences of using it or for
  10.    whether it serves any particular purpose or works at all, unless he
  11.    says so in writing.  Refer to the GNU Emacs General Public License
  12.    for full details.
  13.  
  14.    Everyone is granted permission to copy, modify and redistribute
  15.    Makeinfo, but only under the conditions described in the GNU Emacs
  16.    General Public License.   A copy of this license is supposed to
  17.    have been given to you along with GNU Emacs so you can know your
  18.    rights and responsibilities.  It should be in a file named COPYING.
  19.    Among other things, the copyright notice and this notice must be
  20.    preserved on all copies.  */
  21.  
  22. /* MS-DOS port (c) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet
  23.    This port is also distributed under the terms of the
  24.    GNU General Public License as published by the
  25.    Free Software Foundation.
  26.  
  27.    Please note that this file is not identical to the
  28.    original GNU release, you should have received this
  29.    code as patch to the official release.
  30.  
  31.    $Header: e:/gnu/info/RCS/makeinfo.e 0.1.1.1 90/10/05 11:25:42 tho Exp $
  32.  */
  33.  
  34. /* cont'd from makeinfo.c  */
  35.  
  36. /*===(cut here)===*/
  37.  
  38. /* **************************************************************** */
  39. /*                                    */
  40. /*            Cross Reference Hacking                */
  41. /*                                    */
  42. /* **************************************************************** */
  43.  
  44. char *
  45. get_xref_token ()
  46. {
  47.   char *string;
  48.  
  49.   get_until_in_braces (",", &string);
  50.   if (curchar () == ',')
  51.     input_text_offset++;
  52.   fix_whitespace (string);
  53.   normalize_node_name (string);
  54.   return (string);
  55. }
  56.  
  57. int px_ref_flag = 0;        /* Controls initial output string. */
  58.  
  59. /* Make a cross reference. */
  60. VOID
  61. cm_xref (arg)
  62.      int arg;
  63. {
  64.  
  65.   if (arg == START)
  66.     {
  67.  
  68.       char *arg1, *arg2, *arg3, *arg4, *arg5;
  69.  
  70.       arg1 = get_xref_token ();
  71.       arg2 = get_xref_token ();
  72.       arg3 = get_xref_token ();
  73.       arg4 = get_xref_token ();
  74.       arg5 = get_xref_token ();
  75.  
  76.       add_word_args ("%s", px_ref_flag ? "*note " : "*Note ");
  77.  
  78.       if (*arg5 || *arg4)
  79.     {
  80.       add_word_args ("%s: (%s)%s", arg2, arg4, arg1);
  81.       return;
  82.     }
  83.       else
  84.     remember_node_reference (arg1, line_number, followed_reference);
  85.  
  86.       if (*arg3)
  87.     {
  88.       if (!*arg2)
  89.         {
  90.           add_word_args ("%s: %s", arg3, arg1);
  91.         }
  92.       else
  93.         {
  94.           add_word_args ("%s: %s", arg2, arg1);
  95.         }
  96.       return;
  97.     }
  98.  
  99.       if (*arg2)
  100.     {
  101.       execute_string ("%s", arg2);
  102.       add_word_args (": %s", arg1);
  103.     }
  104.       else
  105.     {
  106.       add_word_args ("%s::", arg1);
  107.     }
  108.  
  109.     }
  110.   else
  111.     {
  112.  
  113.       /* Check to make sure that the next non-whitespace character is either
  114.          a period or a comma. input_text_offset is pointing at the "}" which
  115.          ended the xref or pxref command. */
  116.  
  117.       LONG temp = input_text_offset + 1;
  118.  
  119.       if (output_paragraph[output_paragraph_offset - 2] == ':' &&
  120.       output_paragraph[output_paragraph_offset - 1] == ':')
  121.     return;
  122.       while (temp < size_of_input_text)
  123.     {
  124.       if (cr_or_whitespace (input_text[temp]))
  125.         temp++;
  126.       else
  127.         {
  128.           if (input_text[temp] == '.' ||
  129.           input_text[temp] == ',' ||
  130.           input_text[temp] == '\t')
  131.         return;
  132.           else
  133.         {
  134.           line_error ("Cross-reference must be terminated with a period or a comma");
  135.           return;
  136.         }
  137.         }
  138.     }
  139.     }
  140. }
  141.  
  142. VOID
  143. cm_pxref (arg)
  144.      int arg;
  145. {
  146.   if (arg == START)
  147.     {
  148.       px_ref_flag++;
  149.       cm_xref (arg);
  150.       px_ref_flag--;
  151.     }
  152.   else
  153.     add_char ('.');
  154. }
  155.  
  156. VOID
  157. cm_inforef (arg)
  158.      int arg;
  159. {
  160.   if (arg == START)
  161.     {
  162.       char *node, *pname, *file;
  163.  
  164.       node = get_xref_token ();
  165.       pname = get_xref_token ();
  166.       file = get_xref_token ();
  167.  
  168.       add_word_args ("*note %s: (%s)%s", pname, file, node);
  169.     }
  170. }
  171.  
  172. /* **************************************************************** */
  173. /*                                    */
  174. /*            Insertion Command Stubs                */
  175. /*                                    */
  176. /* **************************************************************** */
  177.  
  178. VOID
  179. cm_quotation ()
  180. {
  181.   begin_insertion (quotation);
  182. }
  183.  
  184. VOID
  185. cm_example ()
  186. {
  187.   begin_insertion (example);
  188. }
  189.  
  190. VOID
  191. cm_smallexample ()
  192. {
  193.   begin_insertion (smallexample);
  194. }
  195.  
  196. VOID
  197. cm_lisp ()
  198. {
  199.   begin_insertion (lisp);
  200. }
  201.  
  202. VOID
  203. cm_format ()
  204. {
  205.   begin_insertion (format);
  206. }
  207.  
  208. VOID
  209. cm_display ()
  210. {
  211.   begin_insertion (display);
  212. }
  213.  
  214. VOID
  215. cm_itemize ()
  216. {
  217.   begin_insertion (itemize);
  218. }
  219.  
  220. VOID
  221. cm_enumerate ()
  222. {
  223.   begin_insertion (enumerate);
  224. }
  225.  
  226. VOID
  227. cm_table ()
  228. {
  229.   begin_insertion (table);
  230. }
  231.  
  232. VOID
  233. cm_group ()
  234. {
  235.   begin_insertion (group);
  236. }
  237.  
  238. VOID
  239. cm_ifinfo ()
  240. {
  241.   begin_insertion (ifinfo);
  242. }
  243.  
  244. VOID
  245. cm_tex ()
  246. {
  247.   discard_until ("\n@end tex");
  248.   discard_until ("\n");
  249. }
  250.  
  251. VOID
  252. cm_iftex ()
  253. {
  254.   discard_until ("\n@end iftex");
  255.   discard_until ("\n");
  256. }
  257.  
  258. VOID
  259. cm_titlespec ()
  260. {
  261.   discard_until ("\n@end titlespec");
  262.   discard_until ("\n");
  263. }
  264.  
  265. VOID
  266. cm_titlepage ()
  267. {
  268.   discard_until ("\n@end titlepage");
  269.   discard_until ("\n");
  270. }
  271.  
  272. VOID
  273. cm_ignore ()
  274. {
  275.   discard_until ("\n@end ignore");
  276.   discard_until ("\n");
  277. }
  278.  
  279. /* **************************************************************** */
  280. /*                                    */
  281. /*            @itemx, @item                    */
  282. /*                                    */
  283. /* **************************************************************** */
  284.  
  285. /* Non-zero means a string is in execution, as opposed to a file. */
  286. int executing_string = 0;
  287.  
  288. /* Execute the string produced by formatting the ARGs with FORMAT.  This
  289.    is like submitting a new file with @include. */
  290. #ifdef MSDOS
  291.  
  292. VOID CDECL
  293. execute_string (char *format, ...)
  294. {
  295.   static char temp_string[4000];
  296.   va_list arg_ptr;
  297.   va_start (arg_ptr, format);
  298.  
  299.   vsprintf (temp_string, format, arg_ptr);
  300.   strcat (temp_string, "@bye\n");
  301.   pushfile ();
  302.   input_text_offset = 0;
  303.   input_text = temp_string;
  304.   input_filename = savestring (input_filename);
  305.   size_of_input_text = strlen (temp_string);
  306.  
  307.   executing_string++;
  308.   reader_loop ();
  309.  
  310.   popfile ();
  311.   executing_string--;
  312.  
  313.   free_and_clear (&command);
  314.   command = savestring ("not bye");
  315. }
  316.  
  317. #else /* not MSDOS */
  318.  
  319. VOID
  320. execute_string (format, arg1, arg2, arg3, arg4, arg5)
  321.      char *format;
  322. {
  323.   static char temp_string[4000];
  324.   sprintf (temp_string, format, arg1, arg2, arg3, arg4, arg5);
  325.   strcat (temp_string, "@bye\n");
  326.   pushfile ();
  327.   input_text_offset = 0;
  328.   input_text = temp_string;
  329.   input_filename = savestring (input_filename);
  330.   size_of_input_text = strlen (temp_string);
  331.  
  332.   executing_string++;
  333.   reader_loop ();
  334.  
  335.   popfile ();
  336.   executing_string--;
  337.  
  338.   free_and_clear (&command);
  339.   command = savestring ("not bye");
  340. }
  341.  
  342. #endif /* not MSDOS */
  343.  
  344. int itemx_flag = 0;
  345.  
  346. VOID
  347. cm_itemx ()
  348. {
  349.   itemx_flag++;
  350.   cm_item ();
  351.   itemx_flag--;
  352. }
  353.  
  354.  
  355. VOID
  356. cm_item ()
  357. {
  358.   char *rest_of_line, *item_func;
  359.  
  360.   /* Can only hack "@item" while inside of an insertion. */
  361.   if (insertion_level)
  362.     {
  363.       get_until ("\n", &rest_of_line);
  364.       canon_white (rest_of_line);
  365.       item_func = current_item_function ();
  366.  
  367.       /* Okay, do the right thing depending on which insertion function
  368.      is active. */
  369.  
  370.       switch (current_insertion_type ())
  371.     {
  372.     case menu:
  373.     case quotation:
  374.     case example:
  375.     case smallexample:
  376.     case lisp:
  377.     case format:
  378.     case display:
  379.     case group:
  380.     case ifinfo:
  381.       line_error ("The `@%s' command is meaningless within a `@%s' block",
  382.               command,
  383.               insertion_type_pname (current_insertion_type ()));
  384.       break;
  385.  
  386.     case itemize:
  387.     case enumerate:
  388.       if (itemx_flag)
  389.         {
  390.           line_error ("@itemx is not meaningful inside of a `%s' block",
  391.               insertion_type_pname (current_insertion_type ()));
  392.         }
  393.       else
  394.         {
  395.           start_paragraph ();
  396.           kill_self_indent (-1);
  397.           discard_until ("\n");
  398.           filling_enabled = indented_fill = true;
  399.  
  400.           if (current_insertion_type () == itemize)
  401.         {
  402.           indent (output_column = current_indent - 2);
  403.  
  404.           /* I need some way to determine whether this command
  405.              takes braces or not.  I believe the user can type
  406.              either "@bullet" or "@bullet{}".  Of course, they
  407.              can also type "o" or "#" or whatever else they want. */
  408.           if (item_func && *item_func)
  409.             {
  410.               if (*item_func == '@')
  411.             if (item_func[strlen (item_func) - 1] != '}')
  412.               execute_string ("%s{}", item_func);
  413.             else
  414.               execute_string ("%s", item_func);
  415.               else
  416.             execute_string ("%s", item_func);
  417.             }
  418.           insert (' ');
  419.           output_column++;
  420.         }
  421.           else
  422.         number_item ();
  423.  
  424.           /* Special hack.  This makes close paragraph ignore you until
  425.          the start_paragraph () function has been called. */
  426.           must_start_paragraph = 1;
  427.         }
  428.       break;
  429.  
  430.     case table:
  431.       {
  432.         /* Get rid of extra characters. */
  433.         kill_self_indent (-1);
  434.  
  435.         /* close_paragraph () almost does what we want.  The problem
  436.            is when paragraph_is_open, and last_char_was_newline, and
  437.            the last newline has been turned into a space, because
  438.            filling_enabled. I handle it here. */
  439.         if (last_char_was_newline && filling_enabled && paragraph_is_open)
  440.           insert ('\n');
  441.         close_paragraph ();
  442.  
  443.         /* Indent on a new line, but back up one indentation level. */
  444.         /* force existing indentation. */
  445.         add_char ('i');
  446.         output_paragraph_offset--;
  447.         kill_self_indent (default_indentation_increment + 1);
  448.  
  449.         /* Add item's argument to the line. */
  450.         filling_enabled = false;
  451.         if (!item_func && !(*item_func))
  452.           execute_string ("%s", rest_of_line);
  453.         else
  454.           execute_string ("%s{%s}", item_func, rest_of_line);
  455.  
  456.         /* Start a new line, and let start_paragraph ()
  457.            do the indenting of it for you. */
  458.         close_single_paragraph ();
  459.         indented_fill = filling_enabled = true;
  460.       }
  461.     }
  462.       free (rest_of_line);
  463.     }
  464.   else
  465.     line_error ("@%s found outside of an insertion block", command);
  466. }
  467.  
  468.  
  469. /* **************************************************************** */
  470. /*                                    */
  471. /*            Defun and Friends                   */
  472. /*                                    */
  473. /* **************************************************************** */
  474.  
  475. /* The list of args that were passed to the def**** command. */
  476. char **defun_args = (char **)NULL;
  477.  
  478. /* An alist mapping defun insertion types to the text that we use
  479.    to describe them. */
  480. struct {
  481.   enum insertion_type type;
  482.   char *title;
  483. } type_title_alist[] = {
  484.   { defun, "Function" },
  485.   { defmac, "Macro" },
  486.   { defspec, "Special form" },
  487.   { defopt, "Option" },
  488.   { deffn, (char *)NULL },
  489.   { defvar, "Variable" },
  490.   { (enum insertion_type)0, (char *)NULL }
  491. };
  492.  
  493. /* Return the title string for this type of defun. */
  494. char *
  495. defun_title (type)
  496.      enum insertion_type type;
  497. {
  498.   register int i;
  499.  
  500.   for (i = 0; type_title_alist[i].type || type_title_alist[i].title; i++)
  501.     if (type_title_alist[i].type == type)
  502.       return (type_title_alist[i].title);
  503.   return (char *)NULL;
  504. }
  505.  
  506. /* Return a list of words from the contents of STRING.
  507.    You can group words with braces. */
  508. char **
  509. args_from_string (string)
  510.      char *string;
  511. {
  512.   char **result = (char **) NULL;
  513.   register int i, start, result_index, size;
  514.   int len, skip_til_brace = 0;
  515.  
  516.   i = result_index = size = 0;
  517.  
  518.   /* Get a token, and stuff it into RESULT.  The tokens are split
  519.      at spaces or tabs. */
  520.   while (string[i])
  521.     {
  522.       /* Skip leading whitespace. */
  523.       for (; string[i] && whitespace (string[i]); i++);
  524.  
  525.       start = i;
  526.  
  527.       if (!string[i])
  528.     return (result);
  529.  
  530.       /* If this is a command which takes it's argument in braces, then
  531.      gobble the whole thing. */
  532.       if (string[i] == COMMAND_PREFIX)
  533.     {
  534.       register int j;
  535.       for (j = i; string[j] &&
  536.            !whitespace (string[j]) &&
  537.            string[j] != '{'; j++);
  538.  
  539.       if (string[j] == '{')
  540.         {
  541.           while (string[j] && string[j] != '}')
  542.         j++;
  543.  
  544.           if (string[j])
  545.         j++;
  546.  
  547.           i = j;
  548.           goto add_arg;
  549.         }
  550.     }
  551.       
  552.       if (string[i] == '{' && !whitespace (string[i + 1]))
  553.     {
  554.       skip_til_brace = 1;
  555.       start = ++i;
  556.     }
  557.  
  558.       /* Skip until whitespace or close brace. */
  559.       while (string[i] &&
  560.          ((skip_til_brace && string[i] != '}') ||
  561.           (!skip_til_brace && !whitespace (string[i]))))
  562.     i++;
  563.  
  564.     add_arg:
  565.       len = i - start;
  566.       if (result_index + 2 >= size)
  567.     {
  568.       if (!size)
  569.         result = (char **) xmalloc ((size = 10) * (sizeof (char *)));
  570.       else
  571.         result =
  572.           (char **) xrealloc (result, ((size += 10) * (sizeof (char *))));
  573.     }
  574.       result[result_index] = (char *) xmalloc (1 + len);
  575.       strncpy (result[result_index], string + start, len);
  576.       result[result_index][len] = '\0';
  577.       result_index++;
  578.       result[result_index] = (char *) NULL;
  579.  
  580.       if (skip_til_brace)
  581.     {
  582.       skip_til_brace = 0;
  583.       if (string[i])
  584.         i++;
  585.     }
  586.     }
  587.  
  588.   return (result);
  589. }
  590.  
  591. VOID
  592. get_defun_args ()
  593. {
  594.   register int i;
  595.   char *line;
  596.  
  597.   get_rest_of_line (&line);
  598.  
  599.   if (defun_args)
  600.     {
  601.       for (i = 0; defun_args[i]; i++)
  602.     free (defun_args[i]);
  603.       free (defun_args);
  604.     }
  605.  
  606.   defun_args = args_from_string (line);
  607.   free (line);
  608. }
  609.  
  610. VOID
  611. insert_defun_arg (string, where)
  612.      char *string;
  613.      int where;
  614. {
  615.   register int i;
  616.  
  617.   for (i = 0; defun_args[i]; i++);
  618.   defun_args = (char **)xrealloc (defun_args, (i + 2) * sizeof (char *));
  619.   defun_args[i + 1] = (char *)NULL;
  620.  
  621.   for (; i != where; --i)
  622.     defun_args[i] = defun_args[i - 1];
  623.  
  624.   defun_args[i] = savestring (string);
  625. }
  626.  
  627. /* Make the defun type insertion.
  628.    TYPE says which insertion this is.
  629.    TITLE is the string to describe the object being described, or NULL
  630.    for no title string.
  631.    X_P says not to start a new insertion if non-zero. */
  632. VOID
  633. defun_internal (type, title, x_p)
  634.      enum insertion_type type;
  635.      char *title;
  636.      int x_p;
  637. {
  638.   register int i = 0;
  639.   char *type_name, *func_name;
  640.   int old_no_indent = no_indent;
  641.  
  642.   get_defun_args ();
  643.  
  644.   if (title)
  645.     insert_defun_arg (title, 0);
  646.  
  647.   if (defun_args[0])
  648.     {
  649.       type_name = defun_args[0];
  650.       i++;
  651.  
  652.       if (defun_args[1])
  653.     {
  654.       func_name = defun_args[1];
  655.       i++;
  656.     }
  657.       else
  658.     func_name = "";
  659.     }
  660.   else
  661.     type_name = "";
  662.  
  663.   no_indent = true;
  664.   start_paragraph ();
  665.   execute_string (" * %s: %s", type_name, func_name);
  666.   no_indent = old_no_indent;
  667.  
  668.   for (; defun_args[i]; i++)
  669.     {
  670.       if (*defun_args[i] == '&')
  671.     add_word_args (" %s", defun_args[i]);
  672.       else
  673.     execute_string (" @var{%s}", defun_args[i]);
  674.     }
  675.   add_char ('\n');
  676.   if (type == defvar || type == defopt)
  677.     execute_string ("@vindex %s\n", func_name);
  678.   else
  679.     execute_string ("@findex %s\n", func_name);
  680.  
  681.   if (!x_p)
  682.     begin_insertion (type);
  683. }
  684.  
  685. /* Add an entry for a function, macro, special form, variable, or option.
  686.    If the name of the calling command ends in `x', then this is an extra
  687.    entry included in the body of an insertion of the same type. */
  688. VOID
  689. cm_defun ()
  690. {
  691.   int x_p;
  692.   enum insertion_type type;
  693.   char *title, *temp = savestring (command);
  694.  
  695.   x_p = (command[strlen (command) - 1] == 'x');
  696.  
  697.   if (x_p)
  698.     temp[strlen (temp) - 1] = '\0';
  699.  
  700.   type = find_type_from_name (temp);
  701.   free (temp);
  702.  
  703.   /* If we are adding to an already existing insertion, then make sure
  704.      that we are already in an insertion of type TYPE. */
  705.   if (x_p &&
  706.       (!insertion_level || insertion_stack->insertion != type))
  707.     {
  708.       line_error ("Must be in a `%s' insertion in order to use `%s'x",
  709.           command, command);
  710.       return;
  711.     }
  712.  
  713.   title = defun_title (type);
  714.   defun_internal (type, title, x_p);
  715. }
  716.  
  717. /* End existing insertion block. */
  718. VOID
  719. cm_end ()
  720. {
  721.   char *temp;
  722.   enum insertion_type type;
  723.  
  724.   if (!insertion_level)
  725.     {
  726.       line_error ("Unmatched `@%s'", command);
  727.       return;
  728.     }
  729.   get_rest_of_line (&temp);
  730.   canon_white (temp);
  731.  
  732.   if (strlen (temp) == 0)
  733.     line_error ("`@%s' needs something after it", command);
  734.   type = find_type_from_name (temp);
  735.   if (type == bad_type)
  736.     {
  737.       line_error ("Bad argument to `%s', `%s', using `%s'",
  738.        command, temp, insertion_type_pname (current_insertion_type ()));
  739.     }
  740.   end_insertion (type);
  741.   free (temp);
  742. }
  743.  
  744.  
  745. /* **************************************************************** */
  746. /*                                    */
  747. /*            Other Random Commands                   */
  748. /*                                    */
  749. /* **************************************************************** */
  750.  
  751. /* noindent () used to do something valueable, but it didn't follow the
  752.    spec for noindent in the texinfo manual.  Now it does nothing, which,
  753.    in the case of makeinfo, is correct. */
  754. VOID
  755. cm_noindent ()
  756. {
  757. /*  no_indent = true;
  758.   indented_fill = false; */
  759. }
  760.  
  761. /* I don't know exactly what to do with this.  Should I allow
  762.    someone to switch filenames in the middle of output?  Since the
  763.    file could be partially written, this doesn't seem to make sense.
  764.    Another option: ignore it, since they don't *really* want to
  765.    switch files.  Finally, complain, or at least warn. */
  766. VOID
  767. cm_setfilename ()
  768. {
  769.   char *filename;
  770.   get_rest_of_line (&filename);
  771.   /* warning ("`@%s %s' encountered and ignored", command, filename); */
  772.   free (filename);
  773. }
  774.  
  775. VOID
  776. cm_comment ()
  777. {
  778.   discard_until ("\n");
  779. }
  780.  
  781. VOID
  782. cm_br ()
  783. {
  784.   close_paragraph ();
  785. }
  786.  
  787.  /* Insert the number of blank lines passed as argument. */
  788. VOID
  789. cm_sp ()
  790. {
  791.   int lines;
  792.   char *line;
  793.  
  794.   close_paragraph ();
  795.   get_rest_of_line (&line);
  796.  
  797.   sscanf (line, "%d", &lines);
  798.   while (lines--)
  799.     add_char ('\n');
  800.   free (line);
  801. }
  802.  
  803. VOID
  804. cm_settitle ()
  805. {
  806.   discard_until ("\n");
  807. }
  808.  
  809. VOID
  810. cm_need ()
  811. {
  812. }
  813.  
  814. /* Start a new line with just this text on it.
  815.    Then center the line of text.
  816.    This always ends the current paragraph. */
  817. VOID
  818. cm_center ()
  819. {
  820.   char *line;
  821.  
  822.   close_paragraph ();
  823.   filling_enabled = indented_fill = false;
  824.  
  825.   get_rest_of_line (&line);
  826.  
  827.   if (strlen (line) < fill_column)
  828.     {
  829.       int i = (fill_column - strlen (line)) / 2;
  830.       while (i--)
  831.     insert (' ');
  832.     }
  833.   add_word_args ("%s", line);
  834.   free (line);
  835.   insert ('\n');
  836.   close_paragraph ();
  837.   filling_enabled = true;
  838. }
  839.  
  840. /* Show what an expression returns. */
  841. VOID
  842. cm_result (arg)
  843.      int arg;
  844. {
  845.   if (arg == END)
  846.     add_word ("=>");
  847. }
  848.  
  849. /* What an expression expands to. */
  850. VOID
  851. cm_expansion (arg)
  852.      int arg;
  853. {
  854.   if (arg == END)
  855.     add_word ("==>");
  856. }
  857.  
  858. /* Indicates two expressions are equivalent. */
  859. VOID
  860. cm_equiv (arg)
  861.      int arg;
  862. {
  863.   if (arg == END)
  864.     add_word ("==");
  865. }
  866.  
  867. /* What an expression may print. */
  868. VOID
  869. cm_print (arg)
  870.      int arg;
  871. {
  872.   if (arg == END)
  873.     add_word ("-|");
  874. }
  875.  
  876. /* An error signaled. */
  877. VOID
  878. cm_error (arg)
  879.      int arg;
  880. {
  881.   if (arg == END)
  882.     add_word ("error-->");
  883. }
  884.  
  885. /* The location of point in an example of a buffer. */
  886. VOID
  887. cm_point (arg)
  888.      int arg;
  889. {
  890.   if (arg == END)
  891.     add_word ("-!-");
  892. }
  893.  
  894. /* Start a new line with just this text on it.
  895.    The text is outdented one level if possible. */
  896. VOID
  897. cm_exdent ()
  898. {
  899.   char *line;
  900.   int i = current_indent;
  901.  
  902.   if (current_indent)
  903.     current_indent -= default_indentation_increment;
  904.  
  905.   get_rest_of_line (&line);
  906.   close_single_paragraph ();
  907.   add_word_args ("%s", line);
  908.   current_indent = i;
  909.   free (line);
  910.   close_single_paragraph ();
  911. }
  912.  
  913. VOID
  914. cm_include ()
  915. {
  916.   cm_infoinclude ();
  917. }
  918.  
  919. /* Remember this file, and move onto the next. */
  920. VOID
  921. cm_infoinclude ()
  922. {
  923.   char *filename;
  924.  
  925.   close_paragraph ();
  926.   get_rest_of_line (&filename);
  927.   pushfile ();
  928.  
  929.   /* In verbose mode we print info about including another file. */
  930.   if (verbose_mode)
  931.     {
  932.       register int i = 0;
  933.       register FSTACK *stack = filestack;
  934.  
  935.       for (i = 0, stack = filestack; stack; stack = stack->next, i++);
  936.  
  937.       i *= 2;
  938.  
  939.       printf ("%*s", i, "");
  940.       printf ("%c%s %s\n", COMMAND_PREFIX, command, filename);
  941.       fflush (stdout);
  942.     }
  943.  
  944.   if (!find_and_load (filename))
  945.     {
  946. #ifndef MSDOS
  947.       extern char *sys_errlist[];
  948.       extern int errno, sys_nerr;
  949. #endif /* not MSDOS */
  950.  
  951.       popfile ();
  952.  
  953.       /* Cannot "@include foo", in line 5 of "/wh/bar". */
  954.       line_error ("`%c%s %s': %s", COMMAND_PREFIX, command, filename,
  955.           ((errno < sys_nerr) ?
  956.            sys_errlist[errno] : "Unknown file system error"));
  957.     }
  958.   free (filename);
  959. }
  960.  
  961. /* The other side of a malformed expression. */
  962. VOID
  963. misplaced_brace ()
  964. {
  965.   line_error ("Misplaced `}'");
  966. }
  967.  
  968. /* Don't let the filling algorithm insert extra whitespace here. */
  969. VOID
  970. cm_force_abbreviated_whitespace ()
  971. {
  972. }
  973.  
  974. /* Make the output paragraph end the sentence here, even though it
  975.    looks like it shouldn't.  This also inserts the character which
  976.    invoked it. */
  977. VOID
  978. cm_force_sentence_end ()
  979. {
  980.   add_char (META ((*command)));
  981. }
  982.  
  983. /* Signals end of processing.  Easy to make this happen. */
  984. VOID
  985. cm_bye ()
  986. {
  987.   input_text_offset = size_of_input_text;
  988. }
  989.  
  990. VOID
  991. cm_asis ()
  992. {
  993. }
  994.  
  995. VOID
  996. cm_setchapternewpage ()
  997. {
  998.   discard_until ("\n");
  999. }
  1000.  
  1001.  
  1002. /* **************************************************************** */
  1003. /*                                    */
  1004. /*            Indexing Stuff                    */
  1005. /*                                    */
  1006. /* **************************************************************** */
  1007.  
  1008.  
  1009. /* An index element... */
  1010. typedef struct index_elt
  1011. {
  1012.   struct index_elt *next;
  1013.   char *entry;            /* The index entry itself. */
  1014.   char *node;            /* The node from whence it came. */
  1015. }         INDEX_ELT;
  1016.  
  1017. /* A list of short-names for each index, and the index to that index in our
  1018.    index array, the_indices.  (Sorry, I couldn't resist.) */
  1019. typedef struct
  1020. {
  1021.   char *name;
  1022.   int index;
  1023. }      INDEX_ALIST;
  1024.  
  1025. INDEX_ALIST **name_index_alist = (INDEX_ALIST **) NULL;
  1026.  
  1027. #ifdef MSDOS
  1028. INDEX_ALIST *find_index (char *name);
  1029. #endif /* MSDOS */
  1030.  
  1031. /* An array of pointers.  Each one is for a different index.  The
  1032.    "synindex" command changes which array slot is pointed to by a
  1033.    given "index". */
  1034. INDEX_ELT **the_indices = (INDEX_ELT **) NULL;
  1035.  
  1036. /* The number of defined indices. */
  1037. int defined_indices = 0;
  1038.  
  1039. /* We predefine these. */
  1040. #define program_index 0
  1041. #define function_index 1
  1042. #define concept_index 2
  1043. #define variable_index 3
  1044. #define datatype_index 4
  1045. #define key_index 5
  1046.  
  1047. VOID
  1048. init_indices ()
  1049. {
  1050.   int i;
  1051.  
  1052.   /* Create the default data structures. */
  1053.  
  1054.   /* Initialize data space. */
  1055.   if (!the_indices)
  1056.     {
  1057.       the_indices = (INDEX_ELT **) xmalloc ((1 + defined_indices) *
  1058.                         sizeof (INDEX_ELT *));
  1059.       the_indices[defined_indices] = (INDEX_ELT *) NULL;
  1060.  
  1061.       name_index_alist = (INDEX_ALIST **) xmalloc ((1 + defined_indices) *
  1062.                            sizeof (INDEX_ALIST *));
  1063.       name_index_alist[defined_indices] = (INDEX_ALIST *) NULL;
  1064.     }
  1065.  
  1066.   /* If there were existing indices, get rid of them now. */
  1067.   for (i = 0; i < defined_indices; i++)
  1068.     undefindex (name_index_alist[i]->name);
  1069.  
  1070.   /* Add the default indices. */
  1071.   defindex ("pg");
  1072.   defindex ("fn");
  1073.   defindex ("cp");
  1074.   defindex ("vr");
  1075.   defindex ("tp");
  1076.   defindex ("ky");
  1077. }
  1078.  
  1079. /* Find which element in the known list of indices has this name.
  1080.    Returns -1 if NAME isn't found. */
  1081. find_index_offset (name)
  1082.      char *name;
  1083. {
  1084.   register int i;
  1085.   for (i = 0; i < defined_indices; i++)
  1086.     if (name_index_alist[i] &&
  1087.     stricmp (name, name_index_alist[i]->name) == 0)
  1088.       return (name_index_alist[i]->index);
  1089.   return (-1);
  1090. }
  1091.  
  1092. /* Return a pointer to the entry of (name . index) for this name.
  1093.    Return -1 if the index doesn't exist. */
  1094. INDEX_ALIST *
  1095. find_index (name)
  1096.      char *name;
  1097. {
  1098.   int offset = find_index_offset (name);
  1099.   if (offset > -1)
  1100.     return (name_index_alist[offset]);
  1101.   else
  1102.     return ((INDEX_ALIST *) - 1);
  1103. }
  1104.  
  1105. /* Given an index name, return the offset in the_indices of this index,
  1106.    or -1 if there is no such index. */
  1107. translate_index (name)
  1108.      char *name;
  1109. {
  1110.   INDEX_ALIST *which = find_index (name);
  1111.  
  1112.   if ((LONG) which > -1)
  1113.     return (which->index);
  1114.   else
  1115.     return (-1);
  1116. }
  1117.  
  1118. /* Return the index list which belongs to NAME. */
  1119. INDEX_ELT *
  1120. index_list (name)
  1121.      char *name;
  1122. {
  1123.   int which = translate_index (name);
  1124.   if (which < 0)
  1125.     return ((INDEX_ELT *) - 1);
  1126.   else
  1127.     return (the_indices[which]);
  1128. }
  1129.  
  1130. /* Please release me, let me go... */
  1131. VOID
  1132. free_index (index)
  1133.      INDEX_ELT *index;
  1134. {
  1135.   INDEX_ELT *temp;
  1136.  
  1137.   while ((temp = index) != (INDEX_ELT *) NULL)
  1138.     {
  1139.       free (temp->entry);
  1140.       free (temp->node);
  1141.       index = index->next;
  1142.       free (temp);
  1143.     }
  1144. }
  1145.  
  1146. /* Flush an index by name. */
  1147. undefindex (name)
  1148.      char *name;
  1149. {
  1150.   int i;
  1151.   int which = find_index_offset (name);
  1152.  
  1153.   if (which < 0)
  1154.     return (which);
  1155.  
  1156.   i = name_index_alist[which]->index;
  1157.  
  1158.  
  1159.   free_index (the_indices[i]);
  1160.   the_indices[i] = (INDEX_ELT *) NULL;
  1161.  
  1162.   free (name_index_alist[which]->name);
  1163.   free (name_index_alist[which]);
  1164.   name_index_alist[which] = (INDEX_ALIST *) NULL;
  1165. }
  1166.  
  1167. /* Define an index known as NAME.  We assign the slot number. */
  1168. VOID
  1169. defindex (name)
  1170.      char *name;
  1171. {
  1172.   register int i, slot;
  1173.  
  1174.   /* If it already exists, flush it. */
  1175.   undefindex (name);
  1176.  
  1177.   /* Try to find an empty slot. */
  1178.   slot = -1;
  1179.   for (i = 0; i < defined_indices; i++)
  1180.     if (!name_index_alist[i])
  1181.       {
  1182.     slot = i;
  1183.     break;
  1184.       }
  1185.  
  1186.   if (slot < 0)
  1187.     {
  1188.       /* No such luck.  Make space for another index. */
  1189.       slot = defined_indices;
  1190.       defined_indices++;
  1191.  
  1192.       name_index_alist = (INDEX_ALIST **) xrealloc (name_index_alist,
  1193.                             (1 + defined_indices)
  1194.                           * sizeof (INDEX_ALIST *));
  1195.       the_indices = (INDEX_ELT **) xrealloc (the_indices,
  1196.                          (1 + defined_indices)
  1197.                          * sizeof (INDEX_ELT *));
  1198.     }
  1199.  
  1200.   /* We have a slot.  Start assigning. */
  1201.   name_index_alist[slot] = (INDEX_ALIST *) xmalloc (sizeof (INDEX_ALIST));
  1202.   name_index_alist[slot]->name = savestring (name);
  1203.   name_index_alist[slot]->index = slot;
  1204.  
  1205.   the_indices[slot] = (INDEX_ELT *) NULL;
  1206. }
  1207.  
  1208. /* Add the arguments to the current index command to the index NAME. */
  1209. VOID
  1210. index_add_arg (name)
  1211.      char *name;
  1212. {
  1213.   int which = translate_index (name);
  1214.   char *index_entry;
  1215.  
  1216. /*   close_paragraph (); */
  1217.   get_rest_of_line (&index_entry);
  1218.  
  1219.   if (which < 0)
  1220.     {
  1221.       line_error ("Unknown index reference `%s'", name);
  1222.       free (index_entry);
  1223.     }
  1224.   else
  1225.     {
  1226.       INDEX_ELT *new = (INDEX_ELT *) xmalloc (sizeof (INDEX_ELT));
  1227.       new->next = the_indices[which];
  1228.       new->entry = index_entry;
  1229.       new->node = current_node;
  1230.       the_indices[which] = new;
  1231.     }
  1232. }
  1233.  
  1234. #define INDEX_COMMAND_SUFFIX "index"
  1235.  
  1236. /* The function which user defined index commands call. */
  1237. VOID
  1238. gen_index ()
  1239. {
  1240.   char *name = savestring (command);
  1241.   if (strlen (name) >= strlen ("index"))
  1242.     name[strlen (name) - strlen ("index")] = '\0';
  1243.   index_add_arg (name);
  1244.   free (name);
  1245. }
  1246.  
  1247. /* Define a new index command.  Arg is name of index. */
  1248. VOID
  1249. cm_defindex ()
  1250. {
  1251.   char *name;
  1252.   get_rest_of_line (&name);
  1253.  
  1254.   if ((LONG) find_index (name) > -1)
  1255.     {
  1256.       line_error ("Index `%s' already exists", name);
  1257.       free (name);
  1258.       return;
  1259.     }
  1260.   else
  1261.     {
  1262.       char *temp = (char *) alloca (1 + strlen (name) + strlen ("index"));
  1263.       sprintf (temp, "%sindex", name);
  1264.       define_user_command (temp, gen_index, 0);
  1265.       defindex (name);
  1266.       free (name);
  1267.     }
  1268. }
  1269.  
  1270. /* Append LIST2 to LIST1.  Return the head of the list. */
  1271. INDEX_ELT *
  1272. index_append (head, tail)
  1273.      INDEX_ELT *head, *tail;
  1274. {
  1275.   register INDEX_ELT *t_head = head;
  1276.  
  1277.   if (!t_head)
  1278.     return (tail);
  1279.  
  1280.   while (t_head->next)
  1281.     t_head = t_head->next;
  1282.   t_head->next = tail;
  1283.   return (head);
  1284. }
  1285.  
  1286. /* Expects 2 args, on the same line.  Both are index abbreviations.
  1287.    Make the first one be a synonym for the second one, i.e. make the
  1288.    first one have the same index as the second one. */
  1289. VOID
  1290. cm_synindex ()
  1291. {
  1292.   int redirector, redirectee;
  1293.   char *temp;
  1294.  
  1295.   skip_whitespace ();
  1296.   get_until_in_line (" ", &temp);
  1297.   redirectee = find_index_offset (temp);
  1298.   skip_whitespace ();
  1299.   free_and_clear (&temp);
  1300.   get_until_in_line (" ", &temp);
  1301.   redirector = find_index_offset (temp);
  1302.   free (temp);
  1303.   if (redirector < 0 || redirectee < 0)
  1304.     {
  1305.       line_error ("Unknown index reference");
  1306.     }
  1307.   else
  1308.     {
  1309.       /* I think that we should let the user make indices synonymous to
  1310.          each other without any lossage of info.  This means that one can
  1311.          say @synindex cp dt anywhere in the file, and things that used to
  1312.          be in cp will go into dt. */
  1313.       INDEX_ELT *i1 = the_indices[redirectee], *i2 = the_indices[redirector];
  1314.  
  1315.       if (i1 || i2)
  1316.     {
  1317.       if (i1)
  1318.         the_indices[redirectee] = index_append (i1, i2);
  1319.       else
  1320.         the_indices[redirectee] = index_append (i2, i1);
  1321.     }
  1322.  
  1323.       name_index_alist[redirectee]->index =
  1324.     name_index_alist[redirector]->index;
  1325.     }
  1326. }
  1327.  
  1328. VOID
  1329. cm_pindex ()            /* Pinhead index. */
  1330. {
  1331.   index_add_arg ("pg");
  1332. }
  1333.  
  1334. VOID
  1335. cm_vindex ()            /* variable index */
  1336. {
  1337.   index_add_arg ("vr");
  1338. }
  1339.  
  1340. VOID
  1341. cm_kindex ()            /* key index */
  1342. {
  1343.   index_add_arg ("ky");
  1344. }
  1345.  
  1346. VOID
  1347. cm_cindex ()            /* concept index */
  1348. {
  1349.   index_add_arg ("cp");
  1350. }
  1351.  
  1352. VOID
  1353. cm_findex ()            /* function index */
  1354. {
  1355.   index_add_arg ("fn");
  1356. }
  1357.  
  1358. VOID
  1359. cm_tindex ()            /* data type index */
  1360. {
  1361.   index_add_arg ("tp");
  1362. }
  1363.  
  1364. /* Sorting the index. */
  1365. int CDECL
  1366. index_element_compare (element1, element2)
  1367.      INDEX_ELT **element1, **element2;
  1368. {
  1369.   return (strcmp ((*element1)->entry, (*element2)->entry));
  1370. }
  1371.  
  1372. /* Sort the index passed in INDEX, returning an array of
  1373.    pointers to elements.  The array is terminated with a NULL
  1374.    pointer.  We call qsort because it's supposed to be fast.
  1375.    I think this looks bad. */
  1376. INDEX_ELT **
  1377. sort_index (index)
  1378.      INDEX_ELT *index;
  1379. {
  1380.   INDEX_ELT *temp = index;
  1381.   INDEX_ELT **array;
  1382.   int count = 0;
  1383.  
  1384.   while (temp != (INDEX_ELT *) NULL)
  1385.     {
  1386.       count++;
  1387.       temp = temp->next;
  1388.     }
  1389.  
  1390.   /* We have the length.  Make an array. */
  1391.  
  1392.   array = (INDEX_ELT **) xmalloc ((count + 1) * sizeof (INDEX_ELT *));
  1393.   count = 0;
  1394.   temp = index;
  1395.  
  1396.   while (temp != (INDEX_ELT *) NULL)
  1397.     {
  1398.       array[count++] = temp;
  1399.       temp = temp->next;
  1400.     }
  1401.   array[count] = (INDEX_ELT *) NULL;    /* terminate the array. */
  1402.  
  1403.   /* Sort the array. */
  1404.   qsort (array, count, sizeof (INDEX_ELT *), index_element_compare);
  1405.  
  1406.   return (array);
  1407. }
  1408.  
  1409. /* Takes one arg, a short name of an index to print.
  1410.    Outputs a menu of the sorted elements of the index. */
  1411. VOID
  1412. cm_printindex ()
  1413. {
  1414.   int item;
  1415.   INDEX_ELT *index;
  1416.   INDEX_ELT **array;
  1417.   char *index_name;
  1418.   int old_inhibitions = inhibit_paragraph_indentation;
  1419.   boolean previous_filling_enabled_value = filling_enabled;
  1420.  
  1421.   close_paragraph ();
  1422.   get_rest_of_line (&index_name);
  1423.  
  1424.   index = index_list (index_name);
  1425.   if ((LONG) index < 0)
  1426.     {
  1427.       line_error ("Unknown index name `%s'", index_name);
  1428.       free (index_name);
  1429.       return;
  1430.     }
  1431.   else
  1432.     free (index_name);
  1433.  
  1434.   array = sort_index (index);
  1435.  
  1436.   filling_enabled = false;
  1437.   inhibit_paragraph_indentation = 1;
  1438.   close_paragraph ();
  1439.   add_word ("* Menu:\n\n");
  1440.  
  1441.   for (item = 0; (index = array[item]); item++)
  1442.     {
  1443.       execute_string ("* %s: %s.\n", index->entry, index->node);
  1444.       flush_output ();
  1445.     }
  1446.   free (array);
  1447.   close_paragraph ();
  1448.   filling_enabled = previous_filling_enabled_value;
  1449.   inhibit_paragraph_indentation = old_inhibitions;
  1450. }
  1451.  
  1452.  
  1453. /* **************************************************************** */
  1454. /*                                    */
  1455. /*            Making User Defined Commands            */
  1456. /*                                    */
  1457. /* **************************************************************** */
  1458.  
  1459. VOID
  1460. define_user_command (name, proc, needs_braces_p)
  1461.      char *name;
  1462.      FUNCTION *proc;
  1463.      int needs_braces_p;
  1464. {
  1465.   int slot = user_command_array_len;
  1466.   user_command_array_len++;
  1467.  
  1468.   if (!user_command_array)
  1469.     user_command_array = (COMMAND **) xmalloc (1 * sizeof (COMMAND *));
  1470.  
  1471.   user_command_array = (COMMAND **) xrealloc (user_command_array,
  1472.                           (1 + user_command_array_len) *
  1473.                           sizeof (COMMAND *));
  1474.  
  1475.   user_command_array[slot] = (COMMAND *) xmalloc (sizeof (COMMAND));
  1476.   user_command_array[slot]->name = savestring (name);
  1477.   user_command_array[slot]->proc = proc;
  1478.   user_command_array[slot]->argument_in_braces = needs_braces_p;
  1479. }
  1480.  
  1481. /* Make ALIAS run the named FUNCTION.  Copies properties from FUNCTION. */
  1482. VOID
  1483. define_alias (alias, function)
  1484.      char *alias, *function;
  1485. {
  1486. }
  1487.  
  1488. /* Some support for footnotes. */
  1489.  
  1490. /* Footnotes are a new construct in Info.  We don't know the best method
  1491.    of implementing them for sure, so we present two possiblities.
  1492.  
  1493. MN   1) Make them look like followed references, with the reference
  1494.         destinations in a makeinfo manufactured node or,
  1495.  
  1496. BN   2) Make them appear at the bottom of the node that they originally
  1497.         appeared in.
  1498. */
  1499.  
  1500. #define MN 0
  1501. #define BN 1
  1502.  
  1503. int footnote_style = MN;
  1504. boolean first_footnote_this_node = true;
  1505. int footnote_count = 0;
  1506.  
  1507. /* Set the footnote style based on he style identifier in STRING. */
  1508. VOID
  1509. set_footnote_style (string)
  1510.      char *string;
  1511. {
  1512.   if (stricmp (string, "MN") == 0)
  1513.     {
  1514.       footnote_style = MN;
  1515.       return;
  1516.     }
  1517.  
  1518.   if (stricmp (string, "BN") == 0)
  1519.     {
  1520.       footnote_style = BN;
  1521.       return;
  1522.     }
  1523. }
  1524.  
  1525. typedef struct fn
  1526. {
  1527.   struct fn *next;
  1528.   char *marker;
  1529.   char *note;
  1530. }  FN;
  1531.  
  1532. FN *pending_notes = (FN *) NULL;
  1533.  
  1534. /* A method for remembering footnotes.  Note that this list gets output
  1535.    at the end of the current node. */
  1536. VOID
  1537. remember_note (marker, note)
  1538.      char *marker, *note;
  1539. {
  1540.   FN *temp = (FN *) xmalloc (sizeof (FN));
  1541.  
  1542.   temp->marker = savestring (marker);
  1543.   temp->note = savestring (note);
  1544.   temp->next = pending_notes;
  1545.   pending_notes = temp;
  1546.   footnote_count++;
  1547. }
  1548.  
  1549. /* How to get rid of existing footnotes. */
  1550. VOID
  1551. free_pending_notes ()
  1552. {
  1553.   FN *temp;
  1554.  
  1555.   while ((temp = pending_notes) != (FN *) NULL)
  1556.     {
  1557.       free (temp->marker);
  1558.       free (temp->note);
  1559.       pending_notes = pending_notes->next;
  1560.       free (temp);
  1561.     }
  1562.   first_footnote_this_node = true;
  1563.   footnote_count = 0;
  1564. }
  1565.  
  1566. /* What to do when you see a @footnote construct. */
  1567.  
  1568.  /* Handle a "footnote".
  1569.     footnote *{this is a footnote}
  1570.     where "*" is the marker character for this note. */
  1571. VOID
  1572. cm_footnote ()
  1573. {
  1574.   char *marker;
  1575.   char *note;
  1576.  
  1577.   get_until ("{", &marker);
  1578.   canon_white (marker);
  1579.  
  1580.   /* Read the argument in braces. */
  1581.   if (curchar () != '{')
  1582.     {
  1583.       line_error ("`@%s' expected more than just `%s'.  It needs something in `{...}'", command, marker);
  1584.       free (marker);
  1585.       return;
  1586.     }
  1587.   else
  1588.     {
  1589.       int braces = 1;
  1590.       LONG temp = ++input_text_offset;
  1591.       int len;
  1592.  
  1593.       while (braces)
  1594.     {
  1595.       if (temp == size_of_input_text)
  1596.         {
  1597.           line_error ("No closing brace for footnote `%s'", marker);
  1598.           return;
  1599.         }
  1600.       if (input_text[temp] == '{')
  1601.         braces++;
  1602.       else if (input_text[temp] == '}')
  1603.         braces--;
  1604.       temp++;
  1605.     }
  1606.  
  1607. #ifdef MSDOS
  1608.       assert (temp - input_text_offset < (1L<<16));
  1609.       len = (size_t) (temp - input_text_offset) - 1;
  1610. #else /* not MSDOS */
  1611.       len = (temp - input_text_offset) - 1;
  1612. #endif /* not MSDOS */
  1613.       note = xmalloc (len + 1);
  1614.       strncpy (note, &input_text[input_text_offset], len);
  1615.       note[len] = '\0';
  1616.       input_text_offset = temp;
  1617.     }
  1618.  
  1619.   if (!current_node || !*current_node)
  1620.     {
  1621.       line_error ("Footnote defined without parent node");
  1622.       free (marker);
  1623.       free (note);
  1624.       return;
  1625.     }
  1626.  
  1627.   remember_note (marker, note);
  1628.  
  1629.   switch (footnote_style)
  1630.     {                /* your method should at least insert marker. */
  1631.  
  1632.     case MN:
  1633.       add_word_args ("(%s)", marker);
  1634.       if (first_footnote_this_node)
  1635.     {
  1636.       char *temp_string = xmalloc ((strlen (current_node))
  1637.                        + (strlen ("-Footnotes")) + 1);
  1638.       add_word_args (" (*note %s-Footnotes::)", current_node);
  1639.       strcpy (temp_string, current_node);
  1640.       strcat (temp_string, "-Footnotes");
  1641.       remember_node_reference (temp_string, line_number, followed_reference);
  1642.       free (temp_string);
  1643.       first_footnote_this_node = false;
  1644.     }
  1645.       break;
  1646.  
  1647.     case BN:
  1648.       add_word_args ("(%s)", marker);
  1649.       break;
  1650.  
  1651.     default:
  1652.       break;
  1653.     }
  1654.   free (marker);
  1655.   free (note);
  1656. }
  1657.  
  1658. /* Non-zero means that we are currently in the process of outputting
  1659.    footnotes. */
  1660. int already_outputting_pending_notes = 0;
  1661.  
  1662. /* Output the footnotes.  We are at the end of the current node. */
  1663. VOID
  1664. output_pending_notes ()
  1665. {
  1666.   FN *footnote = pending_notes;
  1667.  
  1668.   if (!pending_notes)
  1669.     return;
  1670.  
  1671.   switch (footnote_style)
  1672.     {
  1673.  
  1674.     case MN:
  1675.       {
  1676.     char *old_current_node = current_node;
  1677.     char *old_command = savestring (command);
  1678.  
  1679.     already_outputting_pending_notes++;
  1680.     execute_string ("@node %s-Footnotes,,,%s\n", current_node, current_node);
  1681.     already_outputting_pending_notes--;
  1682.     current_node = old_current_node;
  1683.     free (command);
  1684.     command = old_command;
  1685.       }
  1686.       break;
  1687.  
  1688.     case BN:
  1689.       close_paragraph ();
  1690.       execute_string ("---------- Footnotes ----------\n\n");
  1691.       break;
  1692.     }
  1693.  
  1694.  
  1695.   /* Handle the footnotes in reverse order. */
  1696.   {
  1697.     FN **array = (FN **) xmalloc ((footnote_count + 1) * sizeof (FN *));
  1698.  
  1699.     array[footnote_count] = (FN *) NULL;
  1700.  
  1701.     while (--footnote_count > -1)
  1702.       {
  1703.     array[footnote_count] = footnote;
  1704.     footnote = footnote->next;
  1705.       }
  1706.  
  1707.     filling_enabled = true;
  1708.     indented_fill = true;
  1709.  
  1710.     while (footnote = array[++footnote_count])
  1711.       {
  1712.  
  1713.     switch (footnote_style)
  1714.       {
  1715.  
  1716.       case MN:
  1717.       case BN:
  1718.         execute_string ("(%s)  %s", footnote->marker, footnote->note);
  1719.         close_paragraph ();
  1720.         break;
  1721.       }
  1722.       }
  1723.     close_paragraph ();
  1724.     free (array);
  1725.   }
  1726. }
  1727.  
  1728. #ifdef MSDOS
  1729. void _huge *
  1730. xhalloc (long size)
  1731. {
  1732.   void _huge *value = (void _huge *) halloc (size, (size_t) 1);
  1733.  
  1734.   if (value == (void HUGE *) 0 )
  1735.     {
  1736.       error ("Virtual memory exhausted! Needed %ld bytes.", size);
  1737.       exit (FATAL);
  1738.     }
  1739.   return value;
  1740. }
  1741.  
  1742.  
  1743. #if 0
  1744. /* Here we do a huge "realloc" by allocating a new block and
  1745.    moving the old block afterwards.  This is *slow*, but should
  1746.    be reliable.  */
  1747.  
  1748. void _huge *
  1749. xhrealloc (void _huge *ptr, long new_size, long old_size)
  1750. {
  1751.   void _huge *value = (void _huge *) halloc (new_size, (size_t)1 );
  1752.  
  1753.   if (!value)
  1754.     {
  1755.       error ("Virtual memory exhausted in realloc ().");
  1756.       abort ();
  1757.     }
  1758.   else
  1759.     {
  1760.       char _huge *dest = value;
  1761.       char _huge *src = ptr;
  1762.  
  1763.       while (old_size > 0L)
  1764.     {
  1765.       unsigned int bytes = (unsigned int) min (0x8000L, old_size);
  1766.       memcpy (dest, src, bytes);
  1767.       old_size -= (long) bytes;
  1768.       dest += (long) bytes;
  1769.       src += (long) bytes;
  1770.     }
  1771.     }
  1772.   hfree (ptr);
  1773.   return value;
  1774. }
  1775. #endif /* not needed */
  1776.  
  1777.  
  1778. long
  1779. hread (int fd, void _huge *buffer, long bytes)
  1780. {
  1781.   long bytes_read = 0L;
  1782.  
  1783.   while (1)
  1784.     {
  1785.       int n = read (fd, buffer, (unsigned int) min (0x4000L, bytes));
  1786.  
  1787.       if (n > 0)
  1788.     {
  1789.       bytes_read += (long) n;
  1790.       bytes -= (long) n;
  1791.       /* we can't say buffer += n here, because we have to make
  1792.          sure that the offset of BUFFER doesn't overflow during
  1793.          the read() system call.  Therefore we add what we read
  1794.          to the segment of BUFFER.  */
  1795.       FP_SEG(buffer) += (n >> 4);
  1796.       FP_OFF(buffer) += (n & 0x0F);
  1797.     }
  1798.       else if (n == 0)
  1799.     return bytes_read;    /* done */
  1800.       else
  1801.     {
  1802.       perror ("Can't read input");
  1803.       exit (FATAL);
  1804.     }
  1805.     }
  1806. }
  1807.  
  1808. #endif /* MSDOS */
  1809.  
  1810.  
  1811. /* 
  1812.  * Local Variables:
  1813.  * mode:C
  1814.  * ChangeLog:ChangeLog
  1815.  * End:
  1816.  */
  1817.